----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 			sneha nidhi
-- 
-- Create Date:    01:13:18 01/21/2011 
-- Design Name: 
-- Module Name:    MAIN_CONTROL - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.numeric_std.all;
USE work.LCSE.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity MAIN_CONTROL is
	Port ( Reset 		: in  STD_LOGIC;
           Clk   		: in  STD_LOGIC;
           --------ROM---------------------------------------
			  ROM_Data 	: in  STD_LOGIC_VECTOR (11 downto 0); --Instruction,data bus program memory
           ROM_Addr 	: out  STD_LOGIC_VECTOR (11 downto 0);--Program_counter, written by main control--address bus program memory
           -----RAM------------------------------------------
			  RAM_Addr 	: out  STD_LOGIC_vector(7 downto 0);--written by main control--adress bus of data memory
			  RAM_CS   	: out  STD_LOGIC;--by main control
           RAM_Write : out  STD_LOGIC;--written by main control
           RAM_OE 	: out  STD_LOGIC;--written by main control
           -------DMA------------------------------------
			  Databus 	: inout  STD_LOGIC_vector(7 downto 0);
           DMA_RQ  	: in  STD_LOGIC;--from the DMA controler
           DMA_ACK 	: out  STD_LOGIC;--from by main control to dma
           SEND_comm : out  STD_LOGIC;--from by main control--transmission of data 
           DMA_READY : in  STD_LOGIC;--from the DMA controller
           -------ALU----------------------------------
			  u_instruction : out alu_op;-- to the alu
			  Index	   	 : in std_logic_vector(7 downto 0);
			  FlagZ     	 : in  STD_LOGIC;
			  FlagC     	 : in  STD_LOGIC;
           FlagN         : in  STD_LOGIC;
           FlagE         : in  STD_LOGIC
			  );

end MAIN_CONTROL;

architecture Behav of MAIN_CONTROL is

--------Internal Signals---------------------------------------------

type state is 			(idle, bus_cont, second_word, fetch, decode, exrd_ram, exwr_ram );

signal c_s, n_s		:state;  --current state , next state

signal ROM_Addr_s 	:STD_LOGIC_VECTOR (11 downto 0);--written by main control--address bus program memory--ROM_Addr
signal RAM_Addr_s 	:STD_LOGIC_vector(7 downto 0);--wr by main control--adress bus of data memory--RAM_Addr
signal DMA_ACK_s 		:STD_LOGIC;--written by main control--DMA_ACK
signal SEND_comm_s 	:STD_LOGIC;--written by main control--SEND_comm
signal Databus_int 	:STD_LOGIC_vector(7 downto 0);
signal alu_op_s		: alu_op;--temporary variable to store the operator value--u_instruction
signal Databus_OE    :STD_LOGIC;

------internal registers---------------
signal inst_reg		:STD_LOGIC_VECTOR (11 downto 0);--instruction register from rom_data


signal second_word_en:boolean;--load the second byte

----------------------------------------------------------------------
signal pc_flag       :STD_LOGIC;
signal inc_pc 			:STD_LOGIC;
signal jmp_pc			:STD_LOGIC_VECTOR (11 downto 0);
signal pc_n				:STD_LOGIC_VECTOR (11 downto 0):=(others=>'0');
signal wr_decode		:STD_LOGIC;
signal RAM_Addr_oe	:STD_LOGIC;

-----------------------------------------------------------------------
begin

process(reset,c_s,FlagZ,FlagC,FlagN,FlagE,DMA_RQ,DMA_READY,Index,ROM_Data,alu_op_s,pc_n,inc_pc,inst_reg,SEND_comm_s,ROM_Addr_s)
		
		begin
			
			---initial assignments---
			ROM_Addr_s			<= (others => '0') after 1 ns;
			RAM_Addr_s			<= (others => '0') after 1 ns;--RAM_Addr
			databus_int			<= (others => '0') after 1 ns;
			
			DMA_ACK_s			<='0' after 1 ns;--DMA_ACK
			
			second_word_en		<= false after 1 ns;--load the second byte
			
			alu_op_s				<= nop after 1 ns;
			RAM_OE				<='0' after 1 ns;
			RAM_Write			<='0' after 1 ns;
			Databus_OE			<='0' after 1 ns;
			RAM_Addr_oe			<='0' after 1 ns;
			
			pc_flag				<='0' after 1 ns;
			inc_pc				<='0' after 1 ns;
			jmp_pc				<=(others => '0') after 1 ns;
			
			n_s <= c_s after 1 ns;
			
		if (Reset='0') then
			n_s <= idle after 1 ns;
			alu_op_s<=nop after 1 ns;
		
		else
		
		jmp_pc <= ROM_Data after 1 ns;
		
		case c_s is

		when idle =>								--check id dma is requesting for the bus
		
			if (DMA_RQ='1') then 				--either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				n_s<=fetch;							--get the inst from the memory 
			end if;	
---------------------------------------------------------------------------------------------------------
		when bus_cont =>																				--dma controller
		
			if((DMA_RQ='1')and not(inst_reg =  X"0" & TYPE_4 & "000000" ))then		--dma rx the data
				DMA_ACK_s<='1' after 1 ns;															--dma is rx the data
				--RAM_OE<='0' after 1 ns;
				RAM_Write<='1' after 1 ns;
				n_s<= bus_cont after 1 ns;
			elsif((DMA_READY='1')and(inst_reg =  X"0" & TYPE_4 & "000000" ))then 	--tx the data
				SEND_comm_s<='1' after 1 ns;														--giv order to the dma to tx the data stored in memory location
				DMA_ACK_s<='0' after 1 ns;
				RAM_OE<='1' after 1 ns;
				--RAM_Write<='0' after 1 ns;
				n_s<= fetch after 1 ns;
			end if;
				
--///////////////////////////////////////////////////////////////////////////////////////////////////	

		when fetch =>
				ROM_Addr_s <= pc_n;
				if(second_word_en= true) then --flag to check if 2nd word is needed
					n_s<= second_word after 1 ns; 
				else 
					wr_decode<='1' after 1 ns;
					n_s<= decode after 1 ns;
				end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////

		when decode =>
				
			if(inst_reg(11 downto 8) = "0000") then
																			--type 1 instruction--1 byte
				if (inst_reg(7 downto 6) = TYPE_1) then
																			--decide the opcode for the instructions
					if (DMA_RQ='1') then 							--either so send or rx data
						n_s<=bus_cont after 1 ns;
					else 
						inc_pc<='1' after 1 ns;
						n_s <= fetch;
					end if;
					if(inst_reg(5 downto 0) = ALU_ADD) then
						alu_op_s <= op_add after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SUB) then
						alu_op_s <= op_sub after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SHIFTL) then
						alu_op_s <= op_shiftl after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_SHIFTR ) then
						alu_op_s <= op_shiftr after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_AND) then
						alu_op_s <= op_and after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_OR) then
						alu_op_s <= op_or after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_XOR) then
						alu_op_s <= op_xor after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPE ) then
						alu_op_s <= op_cmpe after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPG) then
						alu_op_s <= op_cmpg after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_CMPL) then
						alu_op_s <= op_cmpl after 1 ns;
					elsif(inst_reg(5 downto 0) = ALU_ASCII2BIN)then
						alu_op_s <= op_ascii2bin after 1 ns;
					elsif (inst_reg(5 downto 0) = ALU_BIN2ASCII)then
						alu_op_s <= op_bin2ascii after 1 ns;
					end if;
----------------------------------------------------------------------                       
																				-- instruction type 2			
				elsif(inst_reg(7 downto 6) = TYPE_2) then
					if ((inst_reg(5 downto 0) = JMP_UNCOND)or(inst_reg(5 downto 0) = JMP_COND))then --jump inst
						inc_pc<='1' after 1 ns;
						n_s <= fetch after 1 ns;						--it requires two bytes to call
	     				second_word_en<= true after 1 ns;
				 	end if;									
------------------------------------------------------------------------
																							-- instruction type 3--1 byte
				elsif(inst_reg(7 downto 6) = TYPE_3) then
																							-- instruction LD byte size is 1--register to register transfer
					if (inst_reg(5) = LD)then										--load instruction
																							--instruction of type byte size =1	   
						if(inst_reg(4 downto 0) = SRC_ACC & DST_A)then
							alu_op_s <= op_mvacc2a after 1 ns; 					--internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then		 	--either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <=fetch;
							end if;
						elsif(inst_reg(4 downto 0) = SRC_ACC & DST_B)then
							alu_op_s <= op_mvacc2b after 1 ns;					--internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then 			--either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <= fetch;
							end if;
						elsif(inst_reg(4 downto 0) = SRC_ACC & DST_INDX)then
							alu_op_s <= op_mvacc2id after 1 ns;							--internal load registr from LCSE
							if (DMA_RQ='1')or(DMA_READY = '1') then 							--either so send or rx data
								n_s<=bus_cont after 1 ns;
							else 
								inc_pc<='1' after 1 ns;
								n_s <= fetch;
							end if;
						else 
							inc_pc<='1' after 1 ns;
							n_s <=  fetch after 1 ns;											--2 word inst
							second_word_en <= true after 1 ns;
						end if;
																							--write instruction--2 byte cycles
					elsif(inst_reg(5) = WR )then
						if(inst_reg(4 downto 3) = SRC_ACC )then
							inc_pc<='1' after 1 ns;
							n_s <= fetch after 1 ns; 								--2nd word
	     					second_word_en <= true after 1 ns;
						elsif(inst_reg(4 downto 3) = SRC_CONSTANT)then
							inc_pc<='1' after 1 ns;
							n_s <= fetch after 1 ns;									--2nd word
	     					second_word_en <= true after 1 ns;
						end if;
					end if;
----------------------------------------------------------------------------------------------------------------
				-- instruction type 4---tx the data to the rs232
				
				elsif(inst_reg(7 downto 6) = TYPE_4) then
					if(inst_reg(5 downto 0) = "000000") then 						--send comm signal tx  the data
						if(DMA_READY = '1') then										--check is DMA free to transmit the data
							Send_comm_s <= '1' after 1 ns;							-- if free then ready to tx the data
							n_s <= bus_cont after 1 ns;
						end if;
					end if;
				end if;
			end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////
		
		when second_word =>
			if(inst_reg(7 downto 6) = TYPE_2) then
				
				if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
					n_s<=bus_cont after 1 ns;
				else 
					inc_pc<='1' after 1 ns;
					n_s <= fetch;
				end if;
				if(inst_reg(5 downto 0) = JMP_UNCOND) then
					pc_flag<='1' after 1 ns;
					
				elsif(inst_reg(5 downto 0) = JMP_COND) then
					if (FlagZ = '1')then
						pc_flag<='1' after 1 ns;
					end if;
				end if;

			elsif(inst_reg(7 downto 6) = TYPE_3)then
				if(inst_reg(5) = LD) then
																					--load from a constant to a register
					if(inst_reg(4 downto 3) = SRC_CONSTANT) then
						Databus_OE <= '1' after 1 ns;
						Databus_int <= ROM_Data(7 downto 0);			--load the data on the data bus
						
						if (DMA_RQ='1')or(DMA_READY = '1') then		 --either so send or rx data
							n_s<=bus_cont after 1 ns;
						else 
							inc_pc<='1' after 1 ns;
							n_s <=fetch;
						end if;
						
						if(inst_reg(2 downto 0) = DST_ACC) then
							alu_op_s <= op_ldacc;
						elsif(inst_reg(2 downto 0) = DST_A) then
							alu_op_s <= op_lda;										--external load operations
						elsif(inst_reg(2 downto 0) = DST_B) then
							alu_op_s <= op_ldb;										--external load operations
						elsif(inst_reg(2 downto 0) = DST_INDX) then
							alu_op_s <= op_ldid;										--external load operations
						end if;
																				--load from memory to register--read from memory
					elsif(inst_reg(4 downto 3) = SRC_MEM)then  
						RAM_Addr_oe<='1' after 1 ns;
						RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;
						n_s <= exrd_ram after 1 ns;
					elsif(inst_reg(4 downto 3) = SRC_INDXD_MEM)then  
						RAM_Addr_oe<='1' after 1 ns;
						RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;
						n_s <= exrd_ram after 1 ns;
					end if;
																									--execute write to the memory
				elsif(inst_reg(5) = WR)then
					if(inst_reg(2 downto 0) = DST_MEM)then
						n_s <= exwr_ram after 1 ns; 
					elsif(inst_reg(2 downto 0) = DST_INDXD_MEM)then
						n_s <= exwr_ram after 1 ns;
					end if;
				end if;
			end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////		
		
		
		when  exrd_ram=>
			--RAM_Write <= '0' after 1 ns;
			RAM_OE <= '1' after 1 ns;
			inc_pc<='1' after 1 ns;
			
			if (DMA_RQ='1')or(DMA_READY = '1') then --either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				inc_pc<='1' after 1 ns;
				n_s <=fetch;
			end if;
			
			if (inst_reg(4 downto 3) = SRC_INDXD_MEM)then  
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) + Index after 1 ns;
			else 
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;--src memory read
			end if;
			
			if(inst_reg(2 downto 0) =DST_ACC)then
				alu_op_s <= op_ldacc after 1 ns;
			elsif(inst_reg(2 downto 0) = DST_A)then
				alu_op_s <= op_lda after 1 ns;	
			elsif(inst_reg(2 downto 0) = DST_B)then
				alu_op_s <= op_ldb after 1 ns;
			elsif(inst_reg(2 downto 0) = DST_INDX)then
				alu_op_s <= op_ldid after 1 ns;
			end if;
--///////////////////////////////////////////////////////////////////////////////////////////////////
		
		when exwr_ram=>
		
			RAM_Write <= '1' after 1 ns;
			--RAM_OE <= '0' after 1 ns;
			alu_op_s <= op_oeacc after 1 ns;
			RAM_OE <= '1' after 1 ns;
			
			if (DMA_RQ='1')or(DMA_READY = '1') then 								--either so send or rx data
				n_s<=bus_cont after 1 ns;
			else 
				inc_pc<='1' after 1 ns;
				n_s <= fetch;
			end if;
			
			if (inst_reg(2 downto 0) = DST_INDXD_MEM)then
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) + Index after 1 ns;		--indexed wr
			else 
				RAM_Addr_oe<='1' after 1 ns;
				RAM_Addr_s <= ROM_Data(7 downto 0) after 1 ns;					--simple write
			end if;
		end case;
	end if;
	u_instruction<= alu_op_s after 1 ns;
	ROM_Addr<=ROM_Addr_s after 1 ns;
	SEND_comm<=SEND_comm_s after 1 ns;
	end process;
	


clking: process (Clk,reset) 
		begin
			if(reset='0') then
				pc_n<= (others=>'0') after 1 ns;
				c_s <= idle after 1 ns;
				RAM_CS <= '0';
				DMA_ACK<='0'  after 1 ns;
			elsif (Clk' event and Clk ='1') then	
				c_s <= n_s after 1 ns;
				DMA_ACK<=DMA_ACK_s after 1 ns;
				
				if(wr_decode='1')then
					inst_reg<= ROM_Data after 1 ns;					---instruction to be decoded
				end if;
				
				if(pc_flag='1')then						---jmp
					pc_n<=jmp_pc after 1 ns;
				elsif(inc_pc ='1') then					--increment the pointer
						pc_n <= (pc_n +'1') after 1 ns; --pc_p1
				end if;
			end if;
	end process clking;

  Databus <= Databus_int WHEN Databus_OE = '1' ELSE ("ZZZZZZZZ") after 1 ns;
  RAM_Addr<=RAM_Addr_s when RAM_Addr_oe='1' else ("ZZZZZZZZ") after 1 ns; 

end Behav;

